﻿using System;
using System.Collections.Generic;

namespace Course1
{
    /// <summary>
    /// 委托即函数指针（delegate）
    ///     委托用于指向一个函数
    ///     学习委托的赋值
    ///     多播委托
    ///     委托的执行
    ///     委托的面向对象的本质
    ///         如果一个编程语言不支持委托，可以采用接口的方式类执行
    ///         （委托的本质，C#做了大量的语法糖，甚至提供了关键字，你只需要编写少量的代码即可实现）
    /// 自定义委托
    ///     定义委托
    ///     泛型委托（会自动进行类型推断）
    ///     
    /// 系统内置的委托
    ///     Action:没有返回值的委托
    ///     Func:有返回值的委托
    ///     
    /// 事件
    ///     事件的本质是监听者设计模式
    ///     设计模式：面向对象中，解决问题的方法套路，总结出来的。
    ///     了解常见的设计模式：单例模式，装饰者模式，观察者模式，监听者模式
    /// </summary>
    internal class Example9
    {
        /// <summary>
        /// 多播委托，（委托的本质是观察者模式）
        /// </summary>
        public void Test()
        {
            DoSomething f = (a) => Console.WriteLine("委托1:" + a);
            f += (a) => Console.WriteLine("委托2:" + a);
            f.Invoke("aa");
        }
        /// <summary>
        /// 监听者设计模式
        /// </summary>
        public void Test2()
        {
            var button = new Button();
            button.AddClickListen(new AClickListener());//类似多播
            button.AddClickListen(new BClickListener());
            //点击按钮
            button.Click();

        }
    }
    /// <summary>
    /// 定义一个委托，委托和class是同一级别的东西，可以理解成类型（class）
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    public delegate void DoSomething(string name);
    /// <summary>
    /// 定义一个Conver委托
    /// </summary>
    public delegate int Conver(string number);
    /// <summary>
    /// 委托即函数指针，可以把函数当作参数进行传递
    /// 假设需要你定义一个函数，用于比一个string转换成数字类型，转换逻辑有调用方决定
    /// </summary>
    /// 
    public class Example5Deletage
    {
        private int age;

        public void Test1()
        {
            //定义一个DoSomething类型的变量
            DoSomething a;
            a = Sleep1;//和访问性无关，只要在当前访问可以访问即可（因为当前函数有this，这个委托会使用当前函数的委托）
        }
        public static void Test2()
        {
            //定义一个DoSomething类型的变量
            DoSomething a;
            //a = Sleep1;//静态类中不能赋值一个静态函数，因为没有this（或者说在当前范围内无法访问）
            var ff = new Example5Deletage();
            a = ff.Sleep1;//可以创建一个实列进行赋值，因为实列函数里面有this,函数内部需要this（或者说函数可能用到了this）
        }
        public static void Test3()
        {
            //定义一个DoSomething类型的变量，并同时初始化
            DoSomething a = Sleep2;

        }
        public static void Test4()
        {
            //定义一个DoSomething类型的变量，并同时初始化
            void tt(string name)
            {
            }
            //使用匿名函数
            DoSomething a = tt;

        }
        public static void Test5()
        {
            //使用lambda函数-lambda本质是匿名函数，只不过简化了匿名函数的创建。
            DoSomething a = n =>
            {
            };
        }

        private void Sleep1(string name)
        {
            this.age = 20;
            //这里是有this的
        }

        private static void Sleep2(string name)
        {

        }

    }
  
    public interface IClickListener
    {
        void OnClick(Button button);
    }
    public class AClickListener : IClickListener
    {
        public void OnClick(Button button)
        {
            Console.WriteLine("A监听到了"+button.Name);
        }
    }
    public class BClickListener : IClickListener
    {
        public void OnClick(Button button)
        {
            Console.WriteLine("B监听到了" + button.Name);
        }
    }
    public class Button
    {
        public string Name { get; set; }
        private List<IClickListener> listens = new List<IClickListener>();
        
        public void AddClickListen(IClickListener listen)
        {
            listens.Add(listen);
        }

        public void Click()
        {
            //通知所有监听者
            foreach (var item in listens)
            {
                item.OnClick(this);
            }
        }
    }

    public delegate bool QueryDelegate(int data);
  
    public interface IQueryDelegate
    {
        bool Invoke(int data);
    }
    
    public class List
    {
        private int[] _list = new int[16];
        
        private int _current;
        
        public void Add(int data)
        {
            _list[_current] = data;
            _current++;
        }

        /// <summary>
        /// 委托的方式
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public int[] Where(QueryDelegate query)
        {
            var temp = new int[16];
            int j=0;
            for (int i = 0; i < _current; i++)
            {
                var item = _list[i];
                if (query(item))
                {
                    temp[j] = item;
                    j++;
                }
            }
            return temp;
        }
        /// <summary>
        /// 接口的方式
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public int[] Where(IQueryDelegate query)
        {
            var temp = new int[16];
            int j = 0;
            for (int i = 0; i < _current; i++)
            {
                var item = _list[i];
                if (query.Invoke(item))
                {
                    temp[j] = item;
                    j++;
                }
            }
            return temp;
        }
    }

   
}
